/*
	Copyright: Bernd Schubert <bschubert@ddn.com>
	License: GPLv3

	Decode EAs from Lustre OSTs
*/

#include <stdio.h>
#include <unistd.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <libcfs/posix/posix-types.h>
//#include <lustre/lustre_user.h>

#ifndef ENOATTR
#define ENOATTR		132	/* No such attribute */
#endif

struct ll_fid {
        __u64 id;         /* holds object id */
        __u32 generation; /* holds object generation */
        __u32 f_type;     /* holds object type or stripe idx when passing it to
                           * OST for saving into EA. */
};

struct filter_fid {
	/* ff_fid.f_type == file stripe number (n-th stripe) 
	 * Only if all stripes for the Lustre file are known, the last f_type 
	 * may be used to detect how many stripes the file has */
        struct ll_fid   ff_fid;  
        __u64           ff_objid;
        __u64           ff_group;
};

#define PRINT_FNAME(_fname_) 			\
do {						\
	fprintf(stderr, "%s: ", (_fname_));	\
} while (0)

void lustre_decode(struct filter_fid *fid, char *path)
{
	struct stat buf;
	
	int res = stat(path, &buf);
	if (res == -1) {
		fprintf(stderr, "stat of %s unexpectedly failed: %s\n",
			path, strerror(errno));
		exit(1);
	}

	printf("%s %llu %llu %llu %u %u %u %u %llu\n",
		path, 
		fid->ff_objid, fid->ff_group, 
		fid->ff_fid.id, fid->ff_fid.generation, fid->ff_fid.f_type,
		buf.st_uid, buf.st_gid, (long long unsigned int)buf.st_mtime);
}

int main(int argc, char **argv)
{
	ssize_t res;
	char *path;
	char name[] = "trusted.fid";
	void *buf;
	long size;
	
	if (argc < 2) {
		fprintf(stderr, "Usage: %s filename\n", argv[0]);
		exit(1);
	}

	path = argv[1];

	res = getxattr(path, name, NULL, 0);

	if (res == -1 && errno != ENOATTR) {
		PRINT_FNAME(path);
		fprintf(stderr, "Error getting attribute: %s\n", strerror(errno));
		exit(1);
	}

	if (res == -1) {
		exit (0); // file does not have attribute
	}
	
	if (res == 0) {
		PRINT_FNAME(path);
		fprintf(stderr, "Unexpected result, aborting\n");
		exit(1);
	}

	size = res;

	buf = malloc(size);
	if (buf == NULL) {
		PRINT_FNAME(path);
		fprintf(stderr, "malloc failed: %s\n", strerror(errno));
		exit(1);
	}

	res = getxattr(path, name, buf, size);
	if (res != size) {
		PRINT_FNAME(path);
		fprintf(stderr, "Expected %ld, but got %ld\n", (long)size, (long)res);
		if (res == -1) {
			PRINT_FNAME(path);
			fprintf(stderr, "Failed with %s\n", strerror(errno));
		}
		exit(1);
	}

	lustre_decode(buf, path);

	return 0;
}
